#!/usr/bin/env python3
# encoding: utf-8

__Author__ = '刘仁奎'
__Date__ = '2020-03-31'

"""
参考文档
    - API examples：https://python-gitlab.readthedocs.io/en/stable/api-objects.html
    - python gitlab 接口：https://blog.csdn.net/Destiny_Forever/article/details/88865852
    - 字段：https://python-gitlab.readthedocs.io/en/stable/api/gitlab.v4.html
PyCharts
    - PyCharts文档：http://pyecharts.herokuapp.com/
    - 中文教程：https://pyecharts.org/#/zh-cn/quickstart
"""

import gitlab
import jsonpath
import time
from pyecharts.charts import Bar, Grid
from pyecharts import options as opts
from collections import Counter
from pyecharts.globals import ThemeType

# 提交人
nicks = ['tingfeng', '听风', '刘仁奎']
# 提交时间：自...以来
sinceData = '2020-01-01'
# untilData = '2020-03-20'
untilData = time.strftime("%Y-%m-%d", time.localtime())
# 是否过滤合并代码
filterMerge = True

# 登录
gl = gitlab.Gitlab.from_config('tingfeng', ['python-gitlab.cfg'])


def blank(num: int):
    """
    生成空格
    :param num:
    :return:
    """
    return ''.rjust(num)


def barCommitCharts(data: list, fileName: str):
    """
    生成图表
    :param data:
    :return:
    """
    bar = Bar(init_opts=opts.InitOpts(theme=ThemeType.DARK))
    bar.width = '1500px'
    bar.height = '800px'
    bar.add_xaxis(['提交数', '修改文件数', '修改文件次数', '新增代码', '删除代码', '修改总代码'])
    bar.set_global_opts(title_opts=opts.TitleOpts(title=nicks[0] + "代码提交记录", subtitle=sinceData + '-' + untilData))
    for d in data:
        bar.add_yaxis(d['project'], [d['commitCount'], d['uniqFilesCount'], d['modify'], d['additions'], d['deletions'], d['total']])
    bar.render(fileName)


def barCommitFileCharts(data: list, fileName: str):
    """
    生成文件修改图表
    :param data:
    :return:
    """

    # 图表key
    keys = list()
    counters = []
    for d in data:
        keys.extend(d['uniqFiles'])
        c = Counter(d['allFiles'])
        counters.append({'project': d['project'], 'items': list(c.items())})
    keys = sorted(list(set(keys)))

    # 图表value列表
    for c in counters:
        item = dict(c['items'])
        # 差集，补充没有的key为0
        defKeys = list(set(keys).difference(set(item)))
        for dk in defKeys:
            item[dk] = 0
        c['items'] = dict(sorted(item.items(), key=lambda x: x[0]))

    # 生成图表
    bar = Bar()
    bar.set_global_opts(title_opts=opts.TitleOpts(title=nicks[0] + "文件提交记录", subtitle=sinceData + '-' + untilData),
                        legend_opts=opts.LegendOpts(orient='vertical'),
                        xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=55, interval=0)),
                        datazoom_opts=opts.DataZoomOpts(is_show=True, type_='slider', range_start=10, range_end=30),
                        toolbox_opts=opts.ToolboxOpts(is_show=True, pos_right='2%', feature=opts.ToolBoxFeatureOpts(brush='')))
    bar.add_xaxis(keys)
    for c in counters:
        bar.add_yaxis(c['project'], list(c['items'].values()))

    Grid(
        init_opts=opts.InitOpts(
            width="1800px",
            height="800px",
            animation_opts=opts.AnimationOpts(animation=False)
        )
    ).add(
        bar,
        grid_opts=opts.GridOpts(
            pos_left="10%", pos_right="8%", pos_top="10%", height="60%"
        )
    ).render(fileName)


if __name__ == '__main__':
    print("\n----------- 开始分析 -----------\n")

    # 所有项目提交记录数
    PC_Data = []

    # 1、分组列表
    groups_list = gl.groups.list()
    for group in groups_list:
        print('组名：{} [{}]'.format(group.name, group.id))
        g_projects = group.projects.list(all=True)

        # 2、项目列表
        for g_project in g_projects:
            print("{} 项目：{} [{}]".format(blank(3), g_project.name, g_project.id))
            project = gl.projects.get(g_project.id)

            # 有默认分支
            if hasattr(project, 'default_branch'):
                _commitData = {}
                _uniqFiles = set()
                _allFiles = []
                _modify, _additions, _deletions, _total = 0, 0, 0, 0

                # 3、master 提交记录
                commits = project.commits.list(all=True, since=sinceData, until=untilData)
                for commit in commits:
                    # 我提交的
                    if commit.author_name in nicks:
                        if 'Merge branch' in commit.title and filterMerge:
                            continue
                        print('{} 提交：{} [{}]'.format(blank(6), commit.title, commit.short_id))
                        # 提交详情
                        commitInfo = project.commits.get(commit.short_id)
                        commitDiff = commitInfo.diff()

                        _additions += commitInfo.stats['additions']
                        _deletions += commitInfo.stats['deletions']
                        _total += commitInfo.stats['total']
                        _modify += len(commitDiff)

                        files = jsonpath.jsonpath(commitDiff, '$.*.new_path')
                        for f in files:
                            fileName = f.split("/")[-1]
                            _uniqFiles.add(fileName)
                            _allFiles.append(fileName)

                        print('{} 修改文件数：{}，[{}]'.format(blank(9), len(commitDiff), commitInfo.stats))

                _commitData['project'] = project.name
                _commitData['commitCount'] = len(commits)  # 总提交数
                _commitData['modify'] = _modify  # 未过滤的文件修改总数
                _commitData['allFiles'] = _allFiles  # 未过滤的文件修改总数
                _commitData['uniqFiles'] = _uniqFiles  # 过滤后的文件
                _commitData['uniqFilesCount'] = len(_uniqFiles)  # 过滤后的文件总数
                _commitData['additions'] = _additions
                _commitData['deletions'] = _deletions
                _commitData['total'] = _total
                PC_Data.append(_commitData)

    print("\n----------- 分析完毕 -----------\n")

    for data in PC_Data:
        if data['modify'] > 0:
            print(data)

    # 过滤未改变内容
    PC_Data = [x for x in PC_Data if x['modify'] > 0]
    print('\n共计项目：{} 个，文件数：{}, 修改文件次数：{}，新增代码：{} 行。删除代码：{} 行，总代码：{} 行'.format(len(PC_Data),
                                                                              sum(jsonpath.jsonpath(PC_Data, '$.*.uniqFilesCount')),
                                                                              sum(jsonpath.jsonpath(PC_Data, '$.*.modify')),
                                                                              sum(jsonpath.jsonpath(PC_Data, '$.*.additions')),
                                                                              sum(jsonpath.jsonpath(PC_Data, '$.*.deletions')),
                                                                              sum(jsonpath.jsonpath(PC_Data, '$.*.total'))))

    print("\n----------- 生成图表 -----------")

    # 生成图
    barCommitCharts(PC_Data, 'commit-render.html')
    barCommitFileCharts(PC_Data, 'commit-file-render.html')

    print("\n----------- 图表生成完毕 -----------\n")
